<template>
  <div class="advanced-cropper-container">
    <!-- 圆形预览显示 -->
    <div class="preview-circle" @click="showDialog = true">
      <img v-if="previewImage" :src="previewImage" alt="预览图" />
      <div v-else class="placeholder">
        <el-icon :size="40"><Plus /></el-icon>
        <p>点击上传图片</p>
      </div>
    </div>

    <!-- 裁剪对话框 -->
    <el-dialog
      v-model="showDialog"
      title="高级图片裁剪"
      width="1000px"
      :close-on-click-modal="false"
      @close="handleDialogClose"
    >
      <div class="cropper-content">
        <!-- 文件上传 -->
        <div v-if="!imageUrl" class="upload-area">
          <el-upload
            :auto-upload="false"
            :show-file-list="false"
            :on-change="handleFileChange"
            accept="image/*"
            drag
          >
            <el-icon class="el-icon--upload"><upload-filled /></el-icon>
            <div class="el-upload__text">
              将文件拖到此处，或<em>点击上传</em>
            </div>
            <template #tip>
              <div class="el-upload__tip">支持 jpg/png 格式图片</div>
            </template>
          </el-upload>
        </div>

        <!-- 裁剪区域 -->
        <div v-else class="cropper-area">
          <div class="canvas-wrapper">
            <canvas
              ref="canvas"
              @mousedown="handleMouseDown"
              @mousemove="handleMouseMove"
              @mouseup="handleMouseUp"
              @mouseleave="handleMouseUp"
            ></canvas>
          </div>

          <div class="control-panel">
            <!-- 形状选择 -->
            <div class="control-section">
              <p class="section-title">裁剪形状：</p>
              <el-radio-group v-model="cropShape" @change="handleShapeChange" size="small">
                <el-radio-button label="rectangle">矩形</el-radio-button>
                <el-radio-button label="circle">圆形</el-radio-button>
                <el-radio-button label="ellipse">椭圆</el-radio-button>
                <el-radio-button label="triangle">三角形</el-radio-button>
                <el-radio-button label="star">星形</el-radio-button>
                <el-radio-button label="heart">心形</el-radio-button>
                <el-radio-button label="freehand">自由绘制</el-radio-button>
              </el-radio-group>
            </div>

            <!-- 操作按钮 -->
            <div class="control-section">
              <p class="section-title">操作：</p>
              <div class="button-group">
                <el-button size="small" @click="resetCrop">重置裁剪</el-button>
                <el-button size="small" @click="clearCanvas">清空画布</el-button>
              </div>
              <el-alert
                v-if="cropShape === 'freehand'"
                title="自由绘制模式：按住鼠标左键绘制裁剪路径"
                type="info"
                :closable="false"
                style="margin-top: 10px;"
              />
            </div>

            <!-- 预览 -->
            <div class="control-section">
              <p class="section-title">预览效果：</p>
              <div class="preview-box">
                <canvas ref="previewCanvas" width="200" height="200"></canvas>
              </div>
            </div>
          </div>
        </div>
      </div>

      <template #footer>
        <div class="dialog-footer">
          <el-button @click="handleCancel">取消</el-button>
          <el-button v-if="imageUrl" @click="handleReselect">重新选择</el-button>
          <el-button v-if="imageUrl && hasPath" type="primary" @click="handleCrop">
            确定裁剪
          </el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, onMounted, nextTick, watch } from 'vue';
import { Plus, UploadFilled } from '@element-plus/icons-vue';
import { ElMessage } from 'element-plus';

// 响应式数据
const showDialog = ref(false);
const imageUrl = ref('');
const previewImage = ref('');
const canvas = ref(null);
const previewCanvas = ref(null);
const cropShape = ref('rectangle');
const hasPath = ref(false);

let ctx = null;
let previewCtx = null;
let img = null;
let scale = 1;
let offsetX = 0;
let offsetY = 0;

// 裁剪路径数据
let cropPath = [];
let isDrawing = false;
let cropBox = { x: 0, y: 0, width: 0, height: 0 };

// 处理文件选择
const handleFileChange = (file) => {
  const isImage = file.raw.type.startsWith('image/');
  if (!isImage) {
    ElMessage.error('请上传图片格式文件！');
    return;
  }

  const isLt5M = file.raw.size / 1024 / 1024 < 5;
  if (!isLt5M) {
    ElMessage.error('上传图片大小不能超过 5MB！');
    return;
  }

  const reader = new FileReader();
  reader.onload = (e) => {
    imageUrl.value = e.target.result;
    nextTick(() => {
      initCanvas();
    });
  };
  reader.readAsDataURL(file.raw);
};

// 初始化画布
const initCanvas = () => {
  if (!canvas.value) return;

  ctx = canvas.value.getContext('2d');
  previewCtx = previewCanvas.value.getContext('2d');

  img = new Image();
  img.onload = () => {
    // 设置画布尺寸
    const maxWidth = 600;
    const maxHeight = 500;
    let width = img.width;
    let height = img.height;

    if (width > maxWidth || height > maxHeight) {
      const ratio = Math.min(maxWidth / width, maxHeight / height);
      width = width * ratio;
      height = height * ratio;
    }

    canvas.value.width = width;
    canvas.value.height = height;
    scale = width / img.width;

    drawImage();
    createDefaultCropBox();
  };
  img.src = imageUrl.value;
};

// 绘制图片
const drawImage = () => {
  if (!ctx || !img) return;
  ctx.clearRect(0, 0, canvas.value.width, canvas.value.height);
  ctx.drawImage(img, 0, 0, canvas.value.width, canvas.value.height);
};

// 创建默认裁剪框
const createDefaultCropBox = () => {
  const width = canvas.value.width;
  const height = canvas.value.height;
  const size = Math.min(width, height) * 0.6;

  cropBox = {
    x: (width - size) / 2,
    y: (height - size) / 2,
    width: size,
    height: size,
  };

  hasPath.value = true;
  drawCropShape();
  updatePreview();
};

// 绘制裁剪形状
const drawCropShape = () => {
  drawImage();

  if (!ctx) return;

  ctx.save();

  // 绘制遮罩
  ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
  ctx.fillRect(0, 0, canvas.value.width, canvas.value.height);

  // 设置裁剪路径
  ctx.globalCompositeOperation = 'destination-out';
  ctx.beginPath();

  switch (cropShape.value) {
    case 'rectangle':
      ctx.rect(cropBox.x, cropBox.y, cropBox.width, cropBox.height);
      break;
    case 'circle':
      const radius = Math.min(cropBox.width, cropBox.height) / 2;
      ctx.arc(
        cropBox.x + cropBox.width / 2,
        cropBox.y + cropBox.height / 2,
        radius,
        0,
        Math.PI * 2
      );
      break;
    case 'ellipse':
      ctx.ellipse(
        cropBox.x + cropBox.width / 2,
        cropBox.y + cropBox.height / 2,
        cropBox.width / 2,
        cropBox.height / 2,
        0,
        0,
        Math.PI * 2
      );
      break;
    case 'triangle':
      ctx.moveTo(cropBox.x + cropBox.width / 2, cropBox.y);
      ctx.lineTo(cropBox.x + cropBox.width, cropBox.y + cropBox.height);
      ctx.lineTo(cropBox.x, cropBox.y + cropBox.height);
      ctx.closePath();
      break;
    case 'star':
      drawStar(ctx, cropBox.x + cropBox.width / 2, cropBox.y + cropBox.height / 2, 5, cropBox.width / 2, cropBox.width / 4);
      break;
    case 'heart':
      drawHeart(ctx, cropBox.x + cropBox.width / 2, cropBox.y + cropBox.height / 2, cropBox.width / 2);
      break;
    case 'freehand':
      if (cropPath.length > 0) {
        ctx.moveTo(cropPath[0].x, cropPath[0].y);
        for (let i = 1; i < cropPath.length; i++) {
          ctx.lineTo(cropPath[i].x, cropPath[i].y);
        }
        ctx.closePath();
      }
      break;
  }

  ctx.fill();
  ctx.restore();

  // 绘制裁剪框边框（除了自由绘制模式）
  if (cropShape.value !== 'freehand') {
    ctx.strokeStyle = '#409eff';
    ctx.lineWidth = 2;
    ctx.stroke();
  }
};

// 绘制星形
const drawStar = (ctx, cx, cy, spikes, outerRadius, innerRadius) => {
  let rot = (Math.PI / 2) * 3;
  let x = cx;
  let y = cy;
  const step = Math.PI / spikes;

  ctx.moveTo(cx, cy - outerRadius);
  for (let i = 0; i < spikes; i++) {
    x = cx + Math.cos(rot) * outerRadius;
    y = cy + Math.sin(rot) * outerRadius;
    ctx.lineTo(x, y);
    rot += step;

    x = cx + Math.cos(rot) * innerRadius;
    y = cy + Math.sin(rot) * innerRadius;
    ctx.lineTo(x, y);
    rot += step;
  }
  ctx.lineTo(cx, cy - outerRadius);
  ctx.closePath();
};

// 绘制心形
const drawHeart = (ctx, cx, cy, size) => {
  ctx.moveTo(cx, cy + size / 4);
  ctx.bezierCurveTo(cx, cy, cx - size / 2, cy - size / 2, cx - size / 2, cy);
  ctx.bezierCurveTo(cx - size / 2, cy + size / 4, cx, cy + size / 2, cx, cy + size);
  ctx.bezierCurveTo(cx, cy + size / 2, cx + size / 2, cy + size / 4, cx + size / 2, cy);
  ctx.bezierCurveTo(cx + size / 2, cy - size / 2, cx, cy, cx, cy + size / 4);
  ctx.closePath();
};

// 鼠标事件处理
const handleMouseDown = (e) => {
  if (cropShape.value === 'freehand') {
    isDrawing = true;
    cropPath = [];
    const rect = canvas.value.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;
    cropPath.push({ x, y });
  } else {
    // 矩形等形状的拖动调整大小
    const rect = canvas.value.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;

    // 简单的拖动整个裁剪框
    if (
      x >= cropBox.x &&
      x <= cropBox.x + cropBox.width &&
      y >= cropBox.y &&
      y <= cropBox.y + cropBox.height
    ) {
      isDrawing = true;
      offsetX = x - cropBox.x;
      offsetY = y - cropBox.y;
    }
  }
};

const handleMouseMove = (e) => {
  if (!isDrawing) return;

  const rect = canvas.value.getBoundingClientRect();
  const x = e.clientX - rect.left;
  const y = e.clientY - rect.top;

  if (cropShape.value === 'freehand') {
    cropPath.push({ x, y });
    drawImage();

    // 绘制路径
    ctx.strokeStyle = '#409eff';
    ctx.lineWidth = 2;
    ctx.beginPath();
    ctx.moveTo(cropPath[0].x, cropPath[0].y);
    for (let i = 1; i < cropPath.length; i++) {
      ctx.lineTo(cropPath[i].x, cropPath[i].y);
    }
    ctx.stroke();
  } else {
    // 移动裁剪框
    cropBox.x = Math.max(0, Math.min(x - offsetX, canvas.value.width - cropBox.width));
    cropBox.y = Math.max(0, Math.min(y - offsetY, canvas.value.height - cropBox.height));
    drawCropShape();
    updatePreview();
  }
};

const handleMouseUp = () => {
  if (isDrawing && cropShape.value === 'freehand' && cropPath.length > 2) {
    hasPath.value = true;
    drawCropShape();
    updatePreview();
  }
  isDrawing = false;
};

// 更新预览
const updatePreview = () => {
  if (!previewCtx || !img) return;

  previewCtx.clearRect(0, 0, 200, 200);

  // 创建临时画布用于裁剪
  const tempCanvas = document.createElement('canvas');
  tempCanvas.width = canvas.value.width;
  tempCanvas.height = canvas.value.height;
  const tempCtx = tempCanvas.getContext('2d');

  // 绘制图片
  tempCtx.drawImage(img, 0, 0, canvas.value.width, canvas.value.height);

  // 创建裁剪路径
  tempCtx.globalCompositeOperation = 'destination-in';
  tempCtx.beginPath();

  switch (cropShape.value) {
    case 'rectangle':
      tempCtx.rect(cropBox.x, cropBox.y, cropBox.width, cropBox.height);
      break;
    case 'circle':
      const radius = Math.min(cropBox.width, cropBox.height) / 2;
      tempCtx.arc(
        cropBox.x + cropBox.width / 2,
        cropBox.y + cropBox.height / 2,
        radius,
        0,
        Math.PI * 2
      );
      break;
    case 'ellipse':
      tempCtx.ellipse(
        cropBox.x + cropBox.width / 2,
        cropBox.y + cropBox.height / 2,
        cropBox.width / 2,
        cropBox.height / 2,
        0,
        0,
        Math.PI * 2
      );
      break;
    case 'triangle':
      tempCtx.moveTo(cropBox.x + cropBox.width / 2, cropBox.y);
      tempCtx.lineTo(cropBox.x + cropBox.width, cropBox.y + cropBox.height);
      tempCtx.lineTo(cropBox.x, cropBox.y + cropBox.height);
      tempCtx.closePath();
      break;
    case 'star':
      drawStar(tempCtx, cropBox.x + cropBox.width / 2, cropBox.y + cropBox.height / 2, 5, cropBox.width / 2, cropBox.width / 4);
      break;
    case 'heart':
      drawHeart(tempCtx, cropBox.x + cropBox.width / 2, cropBox.y + cropBox.height / 2, cropBox.width / 2);
      break;
    case 'freehand':
      if (cropPath.length > 0) {
        tempCtx.moveTo(cropPath[0].x, cropPath[0].y);
        for (let i = 1; i < cropPath.length; i++) {
          tempCtx.lineTo(cropPath[i].x, cropPath[i].y);
        }
        tempCtx.closePath();
      }
      break;
  }

  tempCtx.fill();

  // 在预览画布上以圆形显示
  previewCtx.save();
  previewCtx.beginPath();
  previewCtx.arc(100, 100, 100, 0, Math.PI * 2);
  previewCtx.clip();
  previewCtx.drawImage(tempCanvas, 0, 0, 200, 200);
  previewCtx.restore();
};

// 形状改变
const handleShapeChange = () => {
  if (cropShape.value === 'freehand') {
    cropPath = [];
    hasPath.value = false;
    drawImage();
  } else {
    hasPath.value = true;
    createDefaultCropBox();
  }
};

// 重置裁剪
const resetCrop = () => {
  if (cropShape.value === 'freehand') {
    cropPath = [];
    hasPath.value = false;
    drawImage();
  } else {
    createDefaultCropBox();
  }
};

// 清空画布
const clearCanvas = () => {
  cropPath = [];
  hasPath.value = false;
  drawImage();
};

// 确定裁剪
const handleCrop = () => {
  // 创建输出画布
  const outputCanvas = document.createElement('canvas');
  outputCanvas.width = 200;
  outputCanvas.height = 200;
  const outputCtx = outputCanvas.getContext('2d');

  // 创建临时画布
  const tempCanvas = document.createElement('canvas');
  tempCanvas.width = canvas.value.width;
  tempCanvas.height = canvas.value.height;
  const tempCtx = tempCanvas.getContext('2d');

  // 绘制原图
  tempCtx.drawImage(img, 0, 0, canvas.value.width, canvas.value.height);

  // 应用裁剪路径
  tempCtx.globalCompositeOperation = 'destination-in';
  tempCtx.beginPath();

  switch (cropShape.value) {
    case 'rectangle':
      tempCtx.rect(cropBox.x, cropBox.y, cropBox.width, cropBox.height);
      break;
    case 'circle':
      const radius = Math.min(cropBox.width, cropBox.height) / 2;
      tempCtx.arc(
        cropBox.x + cropBox.width / 2,
        cropBox.y + cropBox.height / 2,
        radius,
        0,
        Math.PI * 2
      );
      break;
    case 'ellipse':
      tempCtx.ellipse(
        cropBox.x + cropBox.width / 2,
        cropBox.y + cropBox.height / 2,
        cropBox.width / 2,
        cropBox.height / 2,
        0,
        0,
        Math.PI * 2
      );
      break;
    case 'triangle':
      tempCtx.moveTo(cropBox.x + cropBox.width / 2, cropBox.y);
      tempCtx.lineTo(cropBox.x + cropBox.width, cropBox.y + cropBox.height);
      tempCtx.lineTo(cropBox.x, cropBox.y + cropBox.height);
      tempCtx.closePath();
      break;
    case 'star':
      drawStar(tempCtx, cropBox.x + cropBox.width / 2, cropBox.y + cropBox.height / 2, 5, cropBox.width / 2, cropBox.width / 4);
      break;
    case 'heart':
      drawHeart(tempCtx, cropBox.x + cropBox.width / 2, cropBox.y + cropBox.height / 2, cropBox.width / 2);
      break;
    case 'freehand':
      if (cropPath.length > 0) {
        tempCtx.moveTo(cropPath[0].x, cropPath[0].y);
        for (let i = 1; i < cropPath.length; i++) {
          tempCtx.lineTo(cropPath[i].x, cropPath[i].y);
        }
        tempCtx.closePath();
      }
      break;
  }

  tempCtx.fill();

  // 在输出画布上以圆形显示
  outputCtx.save();
  outputCtx.beginPath();
  outputCtx.arc(100, 100, 100, 0, Math.PI * 2);
  outputCtx.clip();
  outputCtx.drawImage(tempCanvas, 0, 0, 200, 200);
  outputCtx.restore();

  previewImage.value = outputCanvas.toDataURL('image/png');
  showDialog.value = false;
  ElMessage.success('图片裁剪成功！');
  handleDialogClose();
};

// 重新选择
const handleReselect = () => {
  imageUrl.value = '';
  cropPath = [];
  hasPath.value = false;
};

// 取消
const handleCancel = () => {
  showDialog.value = false;
  handleDialogClose();
};

// 对话框关闭
const handleDialogClose = () => {
  if (!previewImage.value) {
    imageUrl.value = '';
    cropPath = [];
    hasPath.value = false;
  }
};
</script>

<style scoped>
.advanced-cropper-container {
  display: inline-block;
}

.preview-circle {
  width: 200px;
  height: 200px;
  border-radius: 50%;
  overflow: hidden;
  border: 2px dashed #d9d9d9;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: border-color 0.3s;
  background-color: #fafafa;
}

.preview-circle:hover {
  border-color: #409eff;
}

.preview-circle img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.placeholder {
  text-align: center;
  color: #8c939d;
}

.placeholder p {
  margin-top: 10px;
  font-size: 14px;
}

.cropper-content {
  min-height: 500px;
}

.upload-area {
  height: 500px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.cropper-area {
  display: flex;
  gap: 20px;
}

.canvas-wrapper {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #f5f5f5;
  border-radius: 4px;
  min-height: 500px;
}

.canvas-wrapper canvas {
  cursor: crosshair;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.control-panel {
  width: 300px;
  display: flex;
  flex-direction: column;
  gap: 15px;
}

.control-section {
  background-color: #f9f9f9;
  padding: 15px;
  border-radius: 4px;
}

.section-title {
  margin: 0 0 12px 0;
  font-size: 14px;
  font-weight: 600;
  color: #303133;
}

.button-group {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.preview-box {
  display: flex;
  justify-content: center;
  margin-top: 10px;
}

.preview-box canvas {
  border: 2px solid #e4e7ed;
  border-radius: 50%;
}

.dialog-footer {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}

:deep(.el-upload-dragger) {
  padding: 40px;
}

:deep(.el-icon--upload) {
  font-size: 67px;
  color: #c0c4cc;
  margin-bottom: 16px;
}

:deep(.el-radio-button__inner) {
  padding: 8px 12px;
  font-size: 12px;
}

:deep(.el-radio-group) {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
}
</style>
